﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OpenTK;

namespace Common {
    public class ObjLoader {

        public static bool LoadObj(string path, List<Vector3> outVertices, List<Vector2> outUvs, List<Vector3> outNormals) {
            Console.WriteLine("Loading obj file {0}...", path);
            var stream = File.Open(path, FileMode.Open);
            using (stream) {
                using (StreamReader streamReader = new StreamReader(stream)) {
                    LoadObjFromStream(streamReader, outVertices, outUvs, outNormals);
                }
            }




            return true;
        }

        private static void LoadObjFromStream(StreamReader reader, List<Vector3> outVertices, List<Vector2> outUvs, List<Vector3> outNormals) {

            List<int> vertexIndices = new List<int>();
            List<int> uvIndices = new List<int>();
            List<int> normalIndices = new List<int>();
            List<Vector3> tempVertices = new List<Vector3>();
            List<Vector2> tempUvs = new List<Vector2>();
            List<Vector3> tempNormals = new List<Vector3>();
            while (true) {
                string line = reader.ReadLine();
                if (line == null) {
                    break;
                }
                parseLine(vertexIndices, uvIndices, normalIndices, tempVertices, tempUvs, tempNormals, line);
            }
            for (int i = 0; i < vertexIndices.Count; i++) {
                int vertexIndex = vertexIndices[i];
                int uvIndex = uvIndices[i];
                int normalIndex = normalIndices[i];

                Vector3 vertex = tempVertices[vertexIndex - 1];
                Vector2 uv = tempUvs[uvIndex - 1];
                Vector3 normal = tempNormals[normalIndex - 1];
                outVertices.Add(vertex);
                outUvs.Add(uv);
                outNormals.Add(normal);
            }

        }

        private static void parseLine(List<int> vertexIndices, List<int> uvIndices, List<int> normalIndices, List<Vector3> tempVertices, List<Vector2> tempUvs, List<Vector3> tempNormals, string line) {
            char space = ' ';
            var words = line.Split(space);
            if (words[0] == "v") {
                Vector3 vertex = readVertex(words);
                tempVertices.Add(vertex);
            }
            else if (words[0] == "vt") {
                Vector2 uv = readUv(words);
                tempUvs.Add(uv);
            }
            else if (words[0] == "vn") {
                Vector3 normal = readNormal(words);
                tempNormals.Add(normal);
            }
            else if (words[0] == "f") {
                if (words.Length != 4) {
                    throw new Exception("File can't be read by our simple parser :-( Try exporting with other options");
                }
                for (int i = 1; i < 4; i++) {
                    string[] group = words[i].Split('/');
                    if (group.Length != 3) {
                        throw new Exception("File can't be read by our simple parser :-( Try exporting with other options");
                    }
                    vertexIndices.Add(int.Parse(group[0]));
                    uvIndices.Add(int.Parse(group[1]));
                    normalIndices.Add(int.Parse(group[2]));
                }
            }
        }

        private static Vector3 readNormal(string[] words) {
            if (words.Length < 4) {
                throw new Exception("format error, normal line should have at least vector3");
            }
            return new Vector3
            {
                X = float.Parse(words[1]),
                Y = float.Parse(words[2]),
                Z = float.Parse(words[3])
            };
        }

        private static Vector2 readUv(string[] words) {
            if (words.Length < 3) {
                throw new Exception("format error, uv line should have at least 2 vector2");
            }
            return new Vector2
            {
                X = float.Parse(words[1]),
                Y = -float.Parse(words[2])
            };
        }

        private static Vector3 readVertex(string[] words) {
            if (words.Length < 4) {
                throw new Exception("file format error, vertex line must have at least 3 vector");
            }
            return new Vector3
            {
                X = float.Parse(words[1]),
                Y = float.Parse(words[2]),
                Z = float.Parse(words[3])
            };
        }
    }
}
